gsktexture: Allow attaching render data to textures
authorBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2016 04:37:20 +0000 (05:37 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2016 16:36:33 +0000 (17:36 +0100)
This allows renderers (or anyone really) to attach "render data" to
textures. Only the first render data sticks.

You can gsk_texture_set_render_data() with the key you will use to
look the data up again, and if no data has been set yet, yours will be
set.

You can retrieve this data via gsk_texture_get_render_data() later on.
If your data has been cleared, NULL will be returned.

When gsk_texture_clear_render_data() is called (which the texture will
call when it is finalized), your destory notify will be called and you
have to release your render data.

The GL driver uses this to attach texture ids to GskTextures.

gsk/gskgldriver.c
gsk/gskgldriverprivate.h
gsk/gskglrenderer.c
gsk/gsktexture.c
gsk/gsktextureprivate.h

index da21f6ae729870b74d7bfcf3a079fcdfdf1058a8..edb6653135782733bcc93d89ac5e61863616ec4e 100644 (file)
@@ -3,6 +3,7 @@
 #include "gskgldriverprivate.h"
 
 #include "gskdebugprivate.h"
+#include "gsktextureprivate.h"
 
 #include <gdk/gdk.h>
 #include <epoxy/gl.h>
@@ -14,8 +15,8 @@ typedef struct {
   GLuint min_filter;
   GLuint mag_filter;
   GArray *fbos;
+  GskTexture *user;
   gboolean in_use : 1;
-  gboolean reserved : 1;
 } Texture;
 
 typedef struct {
@@ -76,7 +77,8 @@ texture_free (gpointer data)
 {
   Texture *t = data;
 
-  g_warn_if_fail (!t->reserved);
+  if (t->user)
+    gsk_texture_clear_render_data (t->user);
 
   g_clear_pointer (&t->fbos, g_array_unref);
   glDeleteTextures (1, &t->texture_id);
@@ -272,7 +274,7 @@ gsk_gl_driver_collect_textures (GskGLDriver *driver)
     {
       Texture *t = value_p;
 
-      if (t->reserved)
+      if (t->user)
         continue;
 
       if (t->in_use)
@@ -383,17 +385,14 @@ find_texture_by_size (GHashTable *textures,
   return NULL;
 }
 
-int
-gsk_gl_driver_create_texture (GskGLDriver *driver,
-                              gboolean     reserve,
-                              int          width,
-                              int          height)
+static Texture *
+create_texture (GskGLDriver *driver,
+                int          width,
+                int          height)
 {
   guint texture_id;
   Texture *t;
 
-  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
-
   if (width >= driver->max_texture_size ||
       height >= driver->max_texture_size)
     {
@@ -406,13 +405,12 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
     }
 
   t = find_texture_by_size (driver->textures, width, height);
-  if (t != NULL && !t->in_use)
+  if (t != NULL && !t->in_use && t->user == NULL)
     {
       GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
                                  t->texture_id, t->width, t->height));
       t->in_use = TRUE;
-      t->reserved = reserve;
-      return t->texture_id;
+      return t;
     }
 
   glGenTextures (1, &texture_id);
@@ -424,25 +422,67 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
   t->min_filter = GL_NEAREST;
   t->mag_filter = GL_NEAREST;
   t->in_use = TRUE;
-  t->reserved = reserve;
   g_hash_table_insert (driver->textures, GINT_TO_POINTER (texture_id), t);
 
-  return t->texture_id;
+  return t;
 }
 
-void
-gsk_gl_driver_release_texture (GskGLDriver *driver,
-                               int          texture_id)
+static void
+gsk_gl_driver_release_texture (gpointer data)
+{
+  Texture *t = data;
+
+  t->user = NULL;
+}
+
+int
+gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver,
+                                       GskTexture  *texture,
+                                       int          min_filter,
+                                       int          mag_filter)
 {
   Texture *t;
+  cairo_surface_t *surface;
+
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
+  g_return_val_if_fail (GSK_IS_TEXTURE (texture), -1);
+
+  t = gsk_texture_get_render_data (texture, driver);
+
+  if (t)
+    {
+      if (t->min_filter == min_filter && t->mag_filter == mag_filter)
+        return t->texture_id;
+    }
   
-  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
-  
-  t = gsk_gl_driver_get_texture (driver, texture_id);
-  g_return_if_fail (t != NULL);
-  g_return_if_fail (t->reserved);
+  t = create_texture (driver, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
+
+  if (gsk_texture_set_render_data (texture, driver, t, gsk_gl_driver_release_texture))
+    t->user = texture;
 
-  t->reserved = FALSE;
+  surface = gsk_texture_download (texture);
+  gsk_gl_driver_bind_source_texture (driver, t->texture_id);
+  gsk_gl_driver_init_texture_with_surface (driver,
+                                           t->texture_id,
+                                           surface,
+                                           min_filter,
+                                           mag_filter);
+
+  return t->texture_id;
+}
+
+int
+gsk_gl_driver_create_texture (GskGLDriver *driver,
+                              int          width,
+                              int          height)
+{
+  Texture *t;
+
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
+
+  t = create_texture (driver, width, height);
+
+  return t->texture_id;
 }
 
 static Vao *
index 636f59c88912226d0a08a8101ac553a8fb9785db..64f9be1f818d8beb6f5344c0d8c8accc7fce7124 100644 (file)
@@ -5,6 +5,8 @@
 #include <gdk/gdk.h>
 #include <graphene.h>
 
+#include <gsk/gsktexture.h>
+
 G_BEGIN_DECLS
 
 #define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
@@ -23,12 +25,13 @@ int             gsk_gl_driver_get_max_texture_size      (GskGLDriver     *driver
 void            gsk_gl_driver_begin_frame               (GskGLDriver     *driver);
 void            gsk_gl_driver_end_frame                 (GskGLDriver     *driver);
 
+int             gsk_gl_driver_get_texture_for_texture   (GskGLDriver     *driver,
+                                                         GskTexture      *texture,
+                                                         int              min_filter,
+                                                         int              mag_filter);
 int             gsk_gl_driver_create_texture            (GskGLDriver     *driver,
-                                                         gboolean         reserved,
                                                          int              width,
                                                          int              height);
-void            gsk_gl_driver_release_texture           (GskGLDriver     *driver,
-                                                         int              texture_id);
 int             gsk_gl_driver_create_vao_for_quad       (GskGLDriver     *driver,
                                                          int              position_id,
                                                          int              uv_id,
index c6824acac9f836c03272c7a534d9f2fc363e6618..6834e32ea802333b107408a811fd99c332a1b527 100644 (file)
@@ -153,7 +153,6 @@ gsk_gl_renderer_create_buffers (GskGLRenderer *self,
   if (self->texture_id == 0)
     {
       self->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
-                                                       FALSE,
                                                        width * scale_factor,
                                                        height * scale_factor);
       gsk_gl_driver_bind_source_texture (self->gl_driver, self->texture_id);
@@ -695,7 +694,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
   if (render_node_needs_render_target (node))
     {
       item.render_data.render_target_id =
-        gsk_gl_driver_create_texture (self->gl_driver, FALSE, item.size.width, item.size.height);
+        gsk_gl_driver_create_texture (self->gl_driver, item.size.width, item.size.height);
       gsk_gl_driver_init_texture_empty (self->gl_driver, item.render_data.render_target_id);
       gsk_gl_driver_create_render_target (self->gl_driver, item.render_data.render_target_id, TRUE, TRUE);
 
@@ -711,22 +710,14 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
   if (gsk_render_node_has_texture (node))
     {
       GskTexture *texture = gsk_render_node_get_texture (node);
-      cairo_surface_t *surface = gsk_texture_download (texture);
       int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
 
       get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
 
-      /* Upload the Cairo surface to a GL texture */
-      item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
-                                                                  FALSE,
-                                                                  item.size.width,
-                                                                  item.size.height);
-      gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
-      gsk_gl_driver_init_texture_with_surface (self->gl_driver,
-                                               item.render_data.texture_id,
-                                               surface,
-                                               gl_min_filter,
-                                               gl_mag_filter);
+      item.render_data.texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
+                                                                           texture,
+                                                                           gl_min_filter,
+                                                                           gl_mag_filter);
     }
   else if (gsk_render_node_has_surface (node))
     {
@@ -737,7 +728,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
 
       /* Upload the Cairo surface to a GL texture */
       item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
-                                                                  FALSE,
                                                                   item.size.width,
                                                                   item.size.height);
       gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
index 8ccfcbac1adcac60d3e447ebdbbf0d89f11db510..ceb36b2e500b7688f33ee5fb733c5f49298f3559 100644 (file)
@@ -35,6 +35,7 @@
 #include "gsktextureprivate.h"
 
 #include "gskdebugprivate.h"
+#include "gskrenderer.h"
 
 /**
  * GskTexture: (ref-func gsk_texture_ref) (unref-func gsk_texture_unref)
@@ -49,6 +50,8 @@ G_DEFINE_BOXED_TYPE(GskTexture, gsk_texture, gsk_texture_ref, gsk_texture_unref)
 static void
 gsk_texture_finalize (GskTexture *self)
 {    
+  gsk_texture_clear_render_data (self);
+
   self->klass->finalize (self);
 
   g_free (self);
@@ -278,3 +281,41 @@ gsk_texture_download (GskTexture *texture)
   return texture->klass->download (texture);
 }
 
+gboolean
+gsk_texture_set_render_data (GskTexture     *self,
+                             gpointer        key,
+                             gpointer        data,
+                             GDestroyNotify  notify)
+{
+  g_return_val_if_fail (data != NULL, FALSE);
+  if (self->render_key != NULL)
+    return FALSE;
+
+  self->render_key = key;
+  self->render_data = data;
+  self->render_notify = notify;
+
+  return TRUE;
+}
+
+void
+gsk_texture_clear_render_data (GskTexture *self)
+{
+  if (self->render_notify)
+    self->render_notify (self->render_data);
+
+  self->render_key = NULL;
+  self->render_data = NULL;
+  self->render_notify = NULL;
+}
+
+gpointer
+gsk_texture_get_render_data (GskTexture  *self,
+                             gpointer     key)
+{
+  if (self->render_key != key)
+    return NULL;
+
+  return self->render_data;
+}
index 78d96de611dc549eea7c78cbebdc659a82fbe8d7..c8d94b67891cc1ff8267d733a0eae63cec740903 100644 (file)
@@ -19,6 +19,10 @@ struct _GskTexture
 
   int width;
   int height;
+
+  gpointer render_key;
+  gpointer render_data;
+  GDestroyNotify render_notify;
 };
 
 struct _GskTextureClass {
@@ -35,6 +39,14 @@ gpointer                gsk_texture_new                 (const GskTextureClass
 GskTexture *            gsk_texture_new_for_surface     (cairo_surface_t        *surface);
 cairo_surface_t *       gsk_texture_download            (GskTexture             *texture);
 
+gboolean                gsk_texture_set_render_data     (GskTexture             *self,
+                                                         gpointer                key,
+                                                         gpointer                data,
+                                                         GDestroyNotify          notify);
+void                    gsk_texture_clear_render_data   (GskTexture             *self);
+gpointer                gsk_texture_get_render_data     (GskTexture             *self,
+                                                         gpointer                key);
+
 G_END_DECLS
 
 #endif /* __GSK_TEXTURE_PRIVATE_H__ */